/*
 * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
 *
 * PROPRIETARY/CONFIDENTIAL
 *
 * This software is the confidential and proprietary information of SAMSUNG
 * ELECTRONICS ("Confidential Information"). You agree and acknowledge that
 * this software is owned by Samsung and you shall not disclose such
 * Confidential Information and shall use it only in accordance with the
 * terms of the license agreement you entered into with SAMSUNG ELECTRONICS.
 * SAMSUNG make no representations or warranties about the suitability of
 * the software, either express or implied, including but not limited to the
 * implied warranties of merchantability, fitness for a particular purpose,
 * or non-infringement. SAMSUNG shall not be liable for any damages suffered
 * by licensee arising out of or related to this software.
 */

#define DEBUG
//#define DEBUG_TO_FILE
//#define DEBUG_MEM

#include <map>
#include <string>
#include <stdio.h>
#include <execinfo.h>
#include <string.h>

static unsigned int g_debug_count;

#ifdef DEBUG

#ifdef DEBUG_TO_FILE
#include <fstream>
#include <iostream>

static void write_log(char *fname,char*log)
{
    std::ofstream g_debug_to_file(fname,std::ofstream::app);
    g_debug_to_file << log;
    g_debug_to_file.flush();
}
#endif//DEBUG_TO_FILE

#ifdef DEBUG_MEM
typedef enum
{
    MEM_FREE,
    MEM_MALLOC,
}MEM_TYPE;

static std::map<std::string,int> g_check_mem_map;
static void CHECK_MEM(const char* _pname,MEM_TYPE _mem_type)
{
    std::map<std::string,int>::iterator iter = g_check_mem_map.find(_pname);
    if(iter == g_check_mem_map.end())
    {
        g_check_mem_map.insert(std::pair<std::string,int>(_pname,_mem_type==MEM_MALLOC?1:-1));
        printf("<memory check>%c %s = [new]\n",_mem_type == MEM_MALLOC?'+':'-',_pname);
    }
    else
    {
        if(_mem_type == MEM_MALLOC)
            iter->second++;
        else
            iter->second--;
        printf("<memory check>%c %s = [%d]\n",_mem_type == MEM_MALLOC?'+':'-',_pname,iter->second);
    }
}
#endif//DEBUG_MEM

#endif//DEBUG


#ifndef __DEBUG_HEAD__
#define __DEBUG_HEAD__
#include <stdlib.h> //for free ,malloc ,etc
#include <stdio.h> //for printf

/* This prevents "deprecated conversion" warnings.. */
//#pragma GCC diagnostic ignored "-Wwrite-strings"

#ifdef __cplusplus
extern "C"{
#endif

typedef enum
{
    DEBUG_LEVEL_FATAL, //fatal
    DEBUG_LEVEL_ERROR, //error
    DEBUG_LEVEL_WARN,  //import information eg.failure but can recover or tell where we are
    DEBUG_LEVEL_DEBUG, //debug ,when found some problem,set this level for more info
    DEBUG_LEVEL_INFO,  //show info in loop
}E_DEBUG_LEVEL;
#define LOG_TAG "ISF"

#ifdef DEBUG
#define DEBUG_LEVEL DEBUG_LEVEL_DEBUG
//#include <assert.h>
static char level_char[6]={'F','E','W','D','i',0};
#ifdef DEBUG_TO_FILE
#define DEBUG_BUFFER_SIZE 500
#ifndef DEBUG_LOGFILE_PATH
#define DEBUG_LOGFILE_PATH "/tmp/smarthome_log.txt"
#endif
//static void write_log(char *fname,char*log);

#define PRINTFUNC(level,fmt, arg...) do {\
    char debug_buffer[DEBUG_BUFFER_SIZE];\
    if(level <= DEBUG_LEVEL)\
    {\
        sprintf(debug_buffer,"%c|%d|%s|%s|%s|%d|"fmt"\n",level_char[level],g_debug_count++,LOG_TAG,__FILE__,__FUNCTION__,__LINE__, ##arg);\
        write_log(DEBUG_LOGFILE_PATH,debug_buffer);\
    }\
} while (0)

#else
#define PRINTFUNC(level,fmt, arg...) do {\
    if(level <= DEBUG_LEVEL)\
    {\
        printf("%c|%d|%s|%s|%s|%d|"fmt"\n",level_char[level],g_debug_count++,LOG_TAG,__FILE__,__FUNCTION__,__LINE__, ##arg);\
    }\
}while(0)

#endif//DEBUG_TO_FILE

#ifdef DEBUG_MEM

#define MY_MALLOC(_name,_point,_type,_size) do {(_point) = (_type)malloc(_size);CHECK_MEM(_name,MEM_MALLOC);} while (0)
#define MY_FREE(_name,_point) do { free(_point);CHECK_MEM(_name,MEM_FREE);} while (0)
#define MY_NEW(_name,_point,_type) do {(_point) = new _type;CHECK_MEM(_name,MEM_MALLOC);} while (0)
#define MY_DELETE(_name,_point) do { delete(_point);CHECK_MEM(_name,MEM_FREE);_point=NULL;} while (0)

#else //DEBUG_MEM
#define MY_MALLOC(_name,_point,_type,_size) do {_point = (_type)malloc(_size);} while (0)
#define MY_FREE(_name,_point) do {free(_point);} while (0)
#define MY_NEW(_name,_point,_type) do {(_point) = new _type;} while (0)
#define MY_DELETE(_name,_point) do { delete(_point);_point=NULL;} while (0)

#endif//DEBUG_MEM

void print_trace(void);
void print_time_start (const char *str_info);
void print_time_end (const char *str_info);
void print_current_time(const char *str_info);


#ifdef LOGF
#undef LOGF
#endif

#ifdef LOGE
#undef LOGE
#endif

#ifdef LOGW
#undef LOGW
#endif

#ifdef LOGD
#undef LOGD
#endif

#ifdef LOGI
#undef LOGI
#endif

#define LOGF(fmt, arg...) PRINTFUNC(DEBUG_LEVEL_FATAL,fmt,##arg)
#define LOGE(fmt, arg...) PRINTFUNC(DEBUG_LEVEL_ERROR,fmt,##arg)
#define LOGW(fmt, arg...) PRINTFUNC(DEBUG_LEVEL_WARN,fmt,##arg)
#define LOGD(fmt, arg...) PRINTFUNC(DEBUG_LEVEL_DEBUG,fmt,##arg)
#define LOGI(fmt, arg...) PRINTFUNC(DEBUG_LEVEL_INFO,fmt,##arg)

#define ASSERT(a,fmt,arg...) {\
    if((a)==false){\
        LOGF(fmt,##arg);\
        exit(1);\
    }\
}\

#else//DEBUG
#include <dlog.h>
#ifndef assert
#define assert(e)
#endif
#define PRINTFUNC_DEBUG_LEVEL_FATAL(fmt, arg...)  LOGF("%d|"fmt"\n",g_debug_count++, ##arg)
#define PRINTFUNC_DEBUG_LEVEL_ERROR(fmt, arg...)  LOGE("%d|"fmt"\n",g_debug_count++, ##arg)
#define PRINTFUNC_DEBUG_LEVEL_WARN(fmt, arg...)   LOGW("%d|"fmt"\n",g_debug_count++, ##arg)
#define PRINTFUNC_DEBUG_LEVEL_DEBUG(fmt, arg...)  LOGI("%d|"fmt"\n",g_debug_count++, ##arg)
#define PRINTFUNC_DEBUG_LEVEL_INFO(fmt, arg...)   LOGD("%d|"fmt"\n",g_debug_count++, ##arg)
#define PRINTFUNC(level,fmt, arg...) PRINTFUNC_##level (fmt, ##arg)

#define MY_MALLOC(_name,_point,_type,_size) do {_point = (_type)malloc(_size);} while (0)
#define MY_FREE(_name,_point) do {free(_point);} while (0)
#define MY_NEW(_name,_point,_type) do {(_point) = new _type;} while (0)
#define MY_DELETE(_name,_point) do { delete(_point);} while (0)
#define print_trace() do {} while (0)
#define print_time_start (a) do {} while (0)
#define print_time_end (a) do {} while (0)
#define print_current_time(a) do {} while (0)

#define ASSERT(a,fmt,arg...) do {} while (0)

#endif//DEBUG



#ifdef __cplusplus
}
#endif
#endif
